#include "linux/gdt.h"
#include "linux/kernel.h"
#include "string.h"

#define GDT_SIZE 256

u64 gdt[GDT_SIZE] = {0};

gdtr32_data_t gdtr32_data;

static void install_x64_code_descriptor(int index)
{
    gdt_item_t* item = (gdt_item_t *) &gdt[index];
    item->limit_low = 0x0;
    item->base_low = 0x0;
    item->type = 0b1000;
    item->segment = 1;
    item->privilege = 0;
    item->present = 1;
    item->limit_high = 0x0;
    item->available = 0;
    item->long_mode = 1;
    item->big = 0;
    item->granularity = 0;
    item->base_high = 0x0;
}

static void install_x64_data_descriptor(int index)
{
    gdt_item_t * item = (gdt_item_t *) &gdt[index];
    item->limit_low = 0x0;
    item->base_low = 0x0;
    item->type = 0x2;
    item->segment = 1;
    item->privilege = 0;
    item->present = 1;
    item->limit_high = 0x0;
    item->available = 0;
    item->long_mode = 1;
    item->big = 0;
    item->granularity = 0;
    item->base_high = 0x0;
}

void install_x64_descriptor()
{
    asm volatile("sgdt gdtr32_data");
    printk("gdt: base:0x%x, limit:0x%x\n", gdtr32_data.base, gdtr32_data.limit);
    memcpy(&gdt, (char*) gdtr32_data.base, gdtr32_data.limit);

    install_x64_code_descriptor(3);
    install_x64_data_descriptor(4);
    gdtr32_data.base = (int) &gdt;
    gdtr32_data.limit = GDT_SIZE * 8 - 1;
    asm volatile("lgdt gdtr32_data");
}